﻿using System;
using System.Drawing;
using System.Windows.Forms;


namespace TextGenerator
{
    /*
     * From:
     * http://stackoverflow.com/questions/1731384/how-to-stop-backgroundworker-on-forms-closing-event
     * http://stackoverflow.com/questions/1755597/c-do-i-need-to-dispose-a-backgroundworker-created-at-runtime
     * http://www.codethinked.com/post/2009/01/11/C-Trivia-What-No-Overflow.aspx
     */
    /// <summary>
    /// The main GUI form.
    /// </summary>
    public partial class MainForm : Form
    {
        /// <summary>
        /// The <see cref="Permutator"/>.
        /// </summary>
        private readonly Permutator permutator = new Permutator(true);

        /// <summary>
        /// A <see cref="Timer"/> used for measuring the total generation process.
        /// </summary>
        private readonly Timer timer = new Timer();

        #region Formatting.
        /// <summary>
        /// The font used to format regular text.
        /// </summary>
        private Font fntRegular = new Font("Courier New", 8, FontStyle.Regular);

        /// <summary>
        /// The font used to format tokens.
        /// </summary>
        private Font fntToken = new Font("Courier New", 8, FontStyle.Bold);
        
        /// <summary>
        /// The font used to format token references.
        /// </summary>
        private Font fntReference = new Font("Courier New", 8, FontStyle.Regular);


        /// <summary>
        /// The color used to format regular text.
        /// </summary>
        private Color clrRegular = Color.Black;

        /// <summary>
        /// The color used to format tokens.
        /// </summary>
        private Color clrToken = Color.ForestGreen;

        /// <summary>
        /// The color used to format token references.
        /// </summary>
        private Color clrReference = Color.DeepPink;
        #endregion Formatting.

 
        /// <summary>
        /// Initializes a new instance of the <see cref="MainForm"/> class. 
        /// </summary>
        public MainForm()
        {
            InitializeComponent();
        }

        #region Form1 Event Handlers.
        private void Form1_Load(object sender, EventArgs e)
        {
            // Turn on double buffering to prevent flickering when resizing.
            this.DoubleBuffered = true;

            // Set the size and location of the split container.
            this.splitContainer1.Dock = DockStyle.Bottom;
            this.splitContainer1.Height = this.splitContainer1.Bottom - this.menuStrip1.Bottom;

            // Set up for performance counting.
            // Get the number of counts per second.
            this.tsslGeneratedIn.Visible = this.timer.CanMeasureTime;

            // Calculate the tab stops.
            int[] tabStops = new int[15];
            for (int i = 0; i < tabStops.Length; i++)
                tabStops[i] = (i + 1) * 20;

            // Initial pattern.
            string pattern = String.Concat(
                "Content type:\t[[Music|Speech]]", Environment.NewLine, 
                "Channels:\t\t[[Mono|Stereo|\"2.1-channels\"|\"Surround\"|\"Ext Surround\"]]", Environment.NewLine, 
                "Format:\t\t\t[[\"Mpeg-1 Layer 3\"|\"Advanced \\\"Audio\\\" Codec\"]]", Environment.NewLine, 
                "File name:\t\t[[\\0]]_[[\\1|1|2|3|6|8]]_channels.[[\\2|\"mp3\"|aac]]", Environment.NewLine
                );

            // Set the pattern settings.
            this.rtbPattern.AcceptsTab = true;
            this.rtbPattern.Multiline = true;
            this.rtbPattern.WordWrap = false;
            this.rtbPattern.AutoWordSelection = true;
            this.rtbPattern.DetectUrls = false;
            this.rtbPattern.ScrollBars = RichTextBoxScrollBars.ForcedBoth;
            this.rtbPattern.Font = this.fntRegular;
            this.rtbPattern.SelectionTabs = tabStops;
            this.rtbPattern.ShowSelectionMargin = true;
            this.rtbPattern.Text = pattern;

            // Set the result settings.
            this.rtbResults.Multiline = true;
            this.rtbResults.WordWrap = false;
            this.rtbResults.AutoWordSelection = true;
            this.rtbResults.DetectUrls = false;
            this.rtbResults.ScrollBars = RichTextBoxScrollBars.ForcedBoth;
            this.rtbResults.Font = this.fntRegular;
            this.rtbResults.SelectionTabs = tabStops;
            this.rtbResults.ShowSelectionMargin = true;

            // Set the Open File Dialog settings.
            this.openFileDialog1.DefaultExt = "txt";
            this.openFileDialog1.Filter = @"Text files (*.txt)|*.txt|All files (*.*)|*.*";
            this.openFileDialog1.InitialDirectory = Application.StartupPath;
            this.openFileDialog1.RestoreDirectory = true;

            // Set the Save File Dialog settings.
            this.saveFileDialog1.DefaultExt = "txt";
            this.saveFileDialog1.FileName = "generated.txt";
            this.saveFileDialog1.Filter = @"Text files (*.txt)|*.txt|All files (*.*)|*.*";
            this.saveFileDialog1.InitialDirectory = Application.StartupPath;
            this.saveFileDialog1.RestoreDirectory = true;

            // Set up the tool strip progressbar.
            this.toolStripProgressBar1.Visible = false;
            this.toolStripProgressBar1.Minimum = 0;
            this.toolStripProgressBar1.Maximum = 100;
            this.toolStripProgressBar1.Value = 0;
            this.toolStripProgressBar1.Alignment = ToolStripItemAlignment.Right;

            // Make the progressbar align to the right.
            // From:
            // http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/e96f9a36-011e-43e0-8dd7-f84d1dfad189/
            this.statusStrip1.LayoutStyle = ToolStripLayoutStyle.HorizontalStackWithOverflow;

            // Hide the statistics label.
            this.tsslStatistics.Visible = false;

            // Reset the result objects.
            ResetResults();
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
//TODO: This is really horrible... Make the SplitContainer sit right below the MenuStrip automatically.
            this.splitContainer1.SuspendLayout();
            this.splitContainer1.Height = this.splitContainer1.Bottom - this.menuStrip1.Bottom;
            this.splitContainer1.ResumeLayout();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // If the asynchronous operation is running, 
            // intercept the event and pause it until 
            // the async operation has been cancelled.
            if (this.asyncWorkIsCompleted) 
                return;

            // Cancel the asynchronous operation.
            this.backgroundWorker1.CancelAsync();

            // Cancel this event.
            // Let the BackgroundWorker's RunWorkerCompleted-event 
            // trigger the closing of the form when it is done.
            e.Cancel = true;

            // Set the flag to indicate (to the BackgroundWorker's 
            // RunWorkerCompleted-event) that the form wants to close.
            this.formClosePending = true;
        }
        #endregion Form1 Event Handlers.

        #region Menu Item Handlers.
        private void openPatternToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult dr = this.openFileDialog1.ShowDialog();
            if (dr != DialogResult.OK)
                return;

            // Get the data.
            string data = OpenFile(this.openFileDialog1.FileName);

            // Display the data.
            if (!String.IsNullOrEmpty(data))
                this.rtbPattern.Text = data;

            // Reset the results.
            ResetResults();
        }

        private void savePatternToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(this.rtbPattern.Text.Trim()))
                return;

            this.saveFileDialog1.FileName = "pattern.txt";
            this.saveFileDialog1.Title = @"Save pattern";

            DialogResult dr = this.saveFileDialog1.ShowDialog();
            if (dr != DialogResult.OK)
                return;

            // Try to save the file.
            // If it did not work, and the user pressed Retry (see SaveFile), 
            // then try again until the user presses Cancel.
            bool success = SaveFile(this.saveFileDialog1.FileName, this.rtbPattern.Text);
            if (!success)
                savePatternToolStripMenuItem_Click(null, null);
        }

        private void saveResultsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(this.rtbResults.Text.Trim()))
                return;

            this.saveFileDialog1.FileName = "generated.txt";
            this.saveFileDialog1.Title = @"Save results";

            DialogResult dr = this.saveFileDialog1.ShowDialog();
            if (dr != DialogResult.OK)
                return;

            // Try to save the file.
            // If it did not work, and the user pressed Retry (see SaveFile), 
            // then try again until the user presses Cancel.
            bool success = SaveFile(this.saveFileDialog1.FileName, this.rtbResults.Text);
            if (!success)
                saveResultsToolStripMenuItem_Click(null, null);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void generateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Validate the pattern.
            string pattern = this.rtbPattern.Text;
            if (String.IsNullOrEmpty(pattern.Trim()))
                return;

            // Prepare the visual elements for generation.
            BeginGeneration();

            // Set the asynchronous work flag to false to 
            // indicate that the operation is running.
            this.asyncWorkIsCompleted = false;

            // Start the asynchronous operation.
            this.backgroundWorker1.RunWorkerAsync(pattern);
        }

        private void cancelOngoingGenerationToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Cancel the asynchronous operation.
            this.backgroundWorker1.CancelAsync();
        }

        private void copyResultsToClipboardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(this.rtbResults.Text))
                return;

            Clipboard.SetText(this.rtbResults.Text, TextDataFormat.Text);
        }

        private void clearResultsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ResetResults();
        }

        private void instructionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form frm = new InstructionsDialog();
            frm.ShowDialog();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form frm = new AboutBox();
            frm.ShowDialog();
        }
        #endregion Menu Item Handlers.

        #region Helper Methods.
        /// <summary>
        /// Resets the result objects.
        /// </summary>
        private void ResetResults()
        {
            this.rtbResults.Text = String.Empty;
            this.tsslGeneratedIn.Text = LABEL_NOT_GENERATED_TEXT;
            this.tsslStatistics.Visible = false;
            this.clearresultsToolStripMenuItem.Enabled = false;
            this.copyResultsToClipboardToolStripMenuItem.Enabled = false;
        }
        #endregion Helper Methods.
   }
}
